これはインタラクティブなノートブックです。ローカルで実行するか、以下のリンクを使用できます:

Chain of Densityを使用した要約

重要な詳細を保持しながら複雑な技術文書を要約することは難しい課題です。Chain of Density(CoD)要約技術は、要約を繰り返し改良してより簡潔で情報密度の高いものにすることで解決策を提供します。このガイドでは、Weaveを使用してアプリケーションの追跡と評価を行いながらCoDを実装する方法を示します。

Chain of Density要約とは何か?

arXiv Chain of Density(CoD)は、徐々に簡潔で情報密度の高い要約を生成する反復的な要約技術です。以下のように機能します:
  1. 初期要約から始める
  2. 要約を繰り返し改良し、重要な情報を保持しながらより簡潔にする
  3. 各反復でエンティティと技術的詳細の密度を高める
このアプローチは、詳細な情報の保持が重要な科学論文や技術文書の要約に特に役立ちます。

なぜWeaveを使用するのか?

このチュートリアルでは、ArXiv論文のChain of Density要約パイプラインを実装し評価するためにWeaveを使用します。以下の方法を学びます:
  1. LLMパイプラインを追跡する: Weaveを使用して、要約プロセスの入力、出力、および中間ステップを自動的に記録します。
  2. LLM出力を評価する: Weaveの組み込みツールを使用して、要約の厳密な同条件での評価を作成します。
  3. 構成可能な操作を構築する: Weave操作を組み合わせて、要約パイプラインの異なる部分で再利用します。
  4. シームレスに統合: 最小限のオーバーヘッドで既存のPythonコードにWeaveを追加します。
このチュートリアルの終わりまでに、モデル提供、評価、結果追跡のためのWeaveの機能を活用するCoDの要約パイプラインを作成することになります。

環境をセットアップする

まず、環境をセットアップし、必要なライブラリをインポートしましょう:
!pip install -qU anthropic weave pydantic requests PyPDF2 set-env-colab-kaggle-dotenv
Anthropic APIキーを取得するには:
  1. アカウントに登録する https://www.anthropic.com
  2. アカウント設定のAPIセクションに移動
  3. 新しいAPIキーを生成
  4. APIキーを.envファイルに安全に保存
import io
import os
from datetime import datetime, timezone

import anthropic
import requests
from pydantic import BaseModel
from PyPDF2 import PdfReader
from set_env import set_env

import weave

set_env("WANDB_API_KEY")
set_env("ANTHROPIC_API_KEY")

weave.init("summarization-chain-of-density-cookbook")
anthropic_client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
私たちは実験を追跡するためにWeaveを使用し、テキスト生成にはAnthropicのClaudeモデルを使用しています。weave.init(<project name>) 呼び出しは、要約タスク用の新しいWeaveプロジェクトをセットアップします。

ArxivPaperモデルを定義する

シンプルな ArxivPaper クラスを作成してデータを表現します:
# Define ArxivPaper model
class ArxivPaper(BaseModel):
    entry_id: str
    updated: datetime
    published: datetime
    title: str
    authors: list[str]
    summary: str
    pdf_url: str

# Create sample ArxivPaper
arxiv_paper = ArxivPaper(
    entry_id="http://arxiv.org/abs/2406.04744v1",
    updated=datetime(2024, 6, 7, 8, 43, 7, tzinfo=timezone.utc),
    published=datetime(2024, 6, 7, 8, 43, 7, tzinfo=timezone.utc),
    title="CRAG -- Comprehensive RAG Benchmark",
    authors=["Xiao Yang", "Kai Sun", "Hao Xin"],  # Truncated for brevity
    summary="Retrieval-Augmented Generation (RAG) has recently emerged as a promising solution...",  # Truncated
    pdf_url="https://arxiv.org/pdf/2406.04744",
)
このクラスはArXiv論文のメタデータとコンテンツをカプセル化し、これが要約パイプラインへの入力となります。

PDFコンテンツを読み込む

論文の全文を扱うために、PDFからテキストを読み込んで抽出する関数を追加します:
@weave.op()
def load_pdf(pdf_url: str) -> str:
    # Download the PDF
    response = requests.get(pdf_url)
    pdf_file = io.BytesIO(response.content)

    # Read the PDF
    pdf_reader = PdfReader(pdf_file)

    # Extract text from all pages
    text = ""
    for page in pdf_reader.pages:
        text += page.extract_text()

    return text

Chain of Density要約を実装する

では、Weave操作を使用してコアとなるCoD要約ロジックを実装しましょう:
# Chain of Density Summarization
@weave.op()
def summarize_current_summary(
    document: str,
    instruction: str,
    current_summary: str = "",
    iteration: int = 1,
    model: str = "claude-3-sonnet-20240229",
):
    prompt = f"""
    Document: {document}
    Current summary: {current_summary}
    Instruction to focus on: {instruction}
    Iteration: {iteration}

    Generate an increasingly concise, entity-dense, and highly technical summary from the provided document that specifically addresses the given instruction.
    """
    response = anthropic_client.messages.create(
        model=model, max_tokens=4096, messages=[{"role": "user", "content": prompt}]
    )
    return response.content[0].text

@weave.op()
def iterative_density_summarization(
    document: str,
    instruction: str,
    current_summary: str,
    density_iterations: int,
    model: str = "claude-3-sonnet-20240229",
):
    iteration_summaries = []
    for iteration in range(1, density_iterations + 1):
        current_summary = summarize_current_summary(
            document, instruction, current_summary, iteration, model
        )
        iteration_summaries.append(current_summary)
    return current_summary, iteration_summaries

@weave.op()
def final_summary(
    instruction: str, current_summary: str, model: str = "claude-3-sonnet-20240229"
):
    prompt = f"""
    Given this summary: {current_summary}
    And this instruction to focus on: {instruction}
    Create an extremely dense, final summary that captures all key technical information in the most concise form possible, while specifically addressing the given instruction.
    """
    return (
        anthropic_client.messages.create(
            model=model, max_tokens=4096, messages=[{"role": "user", "content": prompt}]
        )
        .content[0]
        .text
    )

@weave.op()
def chain_of_density_summarization(
    document: str,
    instruction: str,
    current_summary: str = "",
    model: str = "claude-3-sonnet-20240229",
    density_iterations: int = 2,
):
    current_summary, iteration_summaries = iterative_density_summarization(
        document, instruction, current_summary, density_iterations, model
    )
    final_summary_text = final_summary(instruction, current_summary, model)
    return {
        "final_summary": final_summary_text,
        "accumulated_summary": current_summary,
        "iteration_summaries": iteration_summaries,
    }
各関数の役割は次のとおりです:
  • summarize_current_summary: 現在の状態に基づいて単一の要約イテレーションを生成します。
  • iterative_density_summarization: summarize_current_summary を複数回呼び出すことでCoD技術を適用します。
  • chain_of_density_summarization: 要約プロセス全体を調整し、結果を返します。
@weave.op() デコレータを使用することで、Weaveがこれらの関数の入力、出力、実行を追跡することを保証します。

Weave Modelを作成する

次に、要約パイプラインをWeave Modelでラップしましょう:
# Weave Model
class ArxivChainOfDensityPipeline(weave.Model):
    model: str = "claude-3-sonnet-20240229"
    density_iterations: int = 3

    @weave.op()
    def predict(self, paper: ArxivPaper, instruction: str) -> dict:
        text = load_pdf(paper.pdf_url)
        result = chain_of_density_summarization(
            text,
            instruction,
            model=self.model,
            density_iterations=self.density_iterations,
        )
        return result
この ArxivChainOfDensityPipeline クラスは要約ロジックをWeave Modelとしてカプセル化し、いくつかの重要な利点を提供します:
  1. 自動実験追跡:Weaveはモデルの各実行の入力、出力、パラメータをキャプチャします。
  2. Versioning: Changes to the model’s attributes or code are automatically versioned, creating a clear history of how your summarization pipeline evolves over time.
  3. Reproducibility: The versioning and tracking make it easy to reproduce any previous result or configuration of your summarization pipeline.
  4. ハイパーパラメータ管理:モデル属性(modeldensity_iterations)は明確に定義され、異なる実行間で追跡され、実験を容易にします。
  5. Weaveエコシステムとの統合:weave.Model を使用することで、評価や提供機能などの他のWeaveツールとシームレスに統合できます。

評価指標を実装する

要約の品質を評価するために、シンプルな評価指標を実装します:
import json

@weave.op()
def evaluate_summary(
    summary: str, instruction: str, model: str = "claude-3-sonnet-20240229"
) -> dict:
    prompt = f"""
    Summary: {summary}
    Instruction: {instruction}

    Evaluate the summary based on the following criteria:
    1. Relevance (1-5): How well does the summary address the given instruction?
    2. Conciseness (1-5): How concise is the summary while retaining key information?
    3. Technical Accuracy (1-5): How accurately does the summary convey technical details?

    Your response MUST be in the following JSON format:
    {{
        "relevance": {{
            "score": <int>,
            "explanation": "<string>"
        }},
        "conciseness": {{
            "score": <int>,
            "explanation": "<string>"
        }},
        "technical_accuracy": {{
            "score": <int>,
            "explanation": "<string>"
        }}
    }}

    Ensure that the scores are integers between 1 and 5, and that the explanations are concise.
    """
    response = anthropic_client.messages.create(
        model=model, max_tokens=1000, messages=[{"role": "user", "content": prompt}]
    )
    print(response.content[0].text)

    eval_dict = json.loads(response.content[0].text)

    return {
        "relevance": eval_dict["relevance"]["score"],
        "conciseness": eval_dict["conciseness"]["score"],
        "technical_accuracy": eval_dict["technical_accuracy"]["score"],
        "average_score": sum(eval_dict[k]["score"] for k in eval_dict) / 3,
        "evaluation_text": response.content[0].text,
    }
これらの評価関数は、関連性、簡潔さ、技術的正確さに基づいて生成された要約の品質を評価するためにClaudeモデルを使用します。

Weave Datasetを作成し評価を実行する

パイプラインを評価するために、Weave Datasetを作成し評価を実行します:
# Create a Weave Dataset
dataset = weave.Dataset(
    name="arxiv_papers",
    rows=[
        {
            "paper": arxiv_paper,
            "instruction": "What was the approach to experimenting with different data mixtures?",
        },
    ],
)

weave.publish(dataset)
評価には、LLM-as-a-judgeアプローチを使用します。この手法では、言語モデルを使用して別のモデルやシステムによって生成された出力の品質を評価します。これは、LLMの理解力と推論能力を活用して、特に従来の指標が不十分な場合に、ニュアンスのある評価を提供します。 arXiv
# Define the scorer function
@weave.op()
def quality_scorer(instruction: str, output: dict) -> dict:
    result = evaluate_summary(output["final_summary"], instruction)
    return result
python
# Run evaluation
evaluation = weave.Evaluation(dataset=dataset, scorers=[quality_scorer])
arxiv_chain_of_density_pipeline = ArxivChainOfDensityPipeline()
results = await evaluation.evaluate(arxiv_chain_of_density_pipeline)
このコードは、サンプルのArXiv論文でデータセットを作成し、品質スコアラーを定義し、要約パイプラインの評価を実行します。

結論

この例では、Weaveを使用してArXiv論文のChain of Density要約パイプラインを実装する方法を示しました。以下の方法を示しました:
  1. 要約プロセスの各ステップにWeave操作を作成する
  2. パイプラインをWeave Modelでラップして、簡単な追跡と評価を可能にする
  3. Weave操作を使用してカスタム評価指標を実装する
  4. データセットを作成し、パイプラインの評価を実行する
Weaveのシームレスな統合により、要約プロセス全体を通じて入力、出力、中間ステップを追跡することができ、LLMアプリケーションのデバッグ、最適化、評価が容易になります。 この例を拡張して、より大きなデータセットを処理したり、より洗練された評価指標を実装したり、他のLLMワークフローと統合したりすることができます。 W&Bで完全なレポートを表示